package cn.zhz.privacy.handler;

import cn.hutool.core.util.ReflectUtil;
import cn.zhz.privacy.enums.SerializeType;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Slf4j
public abstract class AbstractHandler<T extends Annotation> implements IEncryptDataHandler {

    private final Class<T> annotationClass;

    public AbstractHandler(Class<T> annotationClass) {
        this.annotationClass = annotationClass;
    }

    protected List<Field> getFieldCache(Class<?> clazz) {
        return loadFields(clazz);
    }

    public boolean canHandleParameter(Class<?> clazz) {
        List<Field> list = getFieldCache(clazz);
        if (list != null && list != NULL_FIELD) {
            return true;
        }
        return false;
    }

    public boolean canHandleResult(Class<?> clazz) {
        List<Field> list = getFieldCache(clazz);
        if (list != null && list != NULL_FIELD) {
            return true;
        }
        return false;
    }

    protected abstract Map<Class<?>, List<Field>> getFieldCache();

    @Override
    public void handleParam(Object parameter) {
    }

    protected List<Field> loadFields(Class<?> clazz) {
        List<Field> fields = getFieldCache().get(clazz);
        // 已处理的类无需再次处理
        if (fields != null) {
            return fields;
        }
        fields = null;
        log.debug("load field:{},{}", clazz, annotationClass);

        Field[] clazzFieldList = ReflectUtil.getFields(clazz);
        for (Field field : clazzFieldList) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            //字段注解
            T annotation = field.getAnnotation(this.annotationClass);
            if (annotation != null) {
                if (fields == null) {
                    fields = new ArrayList<>();
                }
                fields.add(field);
            }
        }
        if (fields == null) {
            fields = NULL_FIELD;
        }
        getFieldCache().put(clazz, fields);
        return fields;
    }

    protected List<Field> NULL_FIELD = new ArrayList<>(0);

    abstract String getAfterValue(T annotation, String originalValue, SerializeType serializeType);

    /**
     * 处理Object
     *
     * @param obj
     * @param oClass
     */
    protected void handleObject(Object obj, Class<?> oClass, SerializeType serializeType) {
        List<Field> fields = loadFields(oClass);
        if (fields == null || fields.isEmpty()) {
            return;
        }
        for (Field field : fields) {
            Object value = ReflectUtil.getFieldValue(obj, field);
            if (value == null || value instanceof Number) {
                continue;
            }
            T annotation = field.getAnnotation(annotationClass);
            if (value instanceof CharSequence) {
                String afterValue = getAfterValue(annotation, (String) value, serializeType);
                ReflectUtil.setFieldValue(obj, field, afterValue);
            } else if (value instanceof Collection) {
                Collection coll = (Collection) value;
                for (Object o : coll) {
                    handleObject(o, o.getClass(), serializeType);
                }
            } else {
                handleObject(value, value.getClass(), serializeType);
            }
        }
    }
}
